"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > 콜백 지옥 이해: 문제, 해결 방법 및 코드 예

콜백 지옥 이해: 문제, 해결 방법 및 코드 예

2024-11-08에 게시됨
검색:389

Understanding Callback Hell: The Problem, Solutions and Code Examples

콜백 지옥은 기술 인터뷰에서도 인기 있는 주제입니다. 개발자의 비동기 코드에 대한 이해도와 더 나은 가독성과 유지 관리성을 위해 코드를 리팩터링하는 능력을 테스트하기 때문입니다.

소개

비동기 프로그래밍은 최신 JavaScript 개발에서 매우 중요하며, 특히 I/O 바인딩 작업의 경우 비차단 실행을 가능하게 하고 성능을 향상시킵니다. 그러나 이러한 편리함은 때때로 "콜백 지옥"이라고 악명 높은 상태로 이어질 수 있습니다.

이 도움말에서는 다음 내용을 자세히 살펴보겠습니다.

  1. 콜백 지옥이 무엇이며 어떻게 발생하는지.
  2. 그것이 만들어내는 문제.
  3. Promise 및 async/await 사용을 포함한 솔루션.
  4. 모든 것을 명확하게 하기 위한 코드 예시.

콜백지옥이란 무엇인가요?

콜백 지옥(종종 "파멸의 피라미드"라고도 함)는 중첩된 여러 비동기 작업이 서로 의존하여 순서대로 실행될 때 발생합니다. 이 시나리오는 깊게 중첩된 콜백의 혼란으로 이어져 코드를 읽고, 유지 관리하고, 디버그하기 어렵게 만듭니다.

콜백 지옥의 예:

getData(function(data) {
  processData(data, function(processedData) {
    saveData(processedData, function(response) {
      sendNotification(response, function(notificationResult) {
        console.log("All done!");
      });
    });
  });
});

위 코드는 여러 비동기 작업을 순차적으로 수행합니다. 작동하는 동안 더 많은 작업이 추가되면 빠르게 관리할 수 없게 되어 이해하고 유지 관리하기가 어려워집니다. 중첩된 구조는 피라미드와 유사하므로 "파멸의 피라미드"라는 용어가 사용됩니다.

콜백 지옥의 문제점

콜백 지옥으로 인해 여러 가지 문제가 발생합니다.

  1. 유지 관리 어려움: 깊게 중첩된 코드는 수정/확장하기 어렵습니다. 새로운 기능을 추가하려고 시도하는 것만으로도 버그가 발생할 수 있습니다.
  2. 오류 처리: 서로 다른 중첩 레이어에 대한 적절한 오류 처리가 복잡해집니다. 개별 콜백마다 오류를 처리해야 하므로 코드가 반복될 수 있습니다.
  3. 코드 가독성: 특히 코드베이스에 익숙하지 않은 개발자의 경우 실행 흐름을 이해하는 것이 어렵습니다.
  4. 확장성: 중첩된 콜백 수가 증가함에 따라 복잡성도 증가하여 코드를 확장할 수 없고 디버그하기 어렵게 만듭니다.

약속: 콜백 지옥에 대한 솔루션

콜백 지옥의 문제를 완화하기 위해 JavaScript에서는 Promises를 사용합니다. 약속은 비동기 작업의 최종 완료(또는 실패)를 나타내며 깔끔하고 관리하기 쉬운 코드를 작성할 수 있게 해줍니다. Promise는 코드를 단순화합니다 - Promise를 사용하면 중첩 구조가 평면화되고 오류 처리가 더욱 중앙 집중화되어 코드를 더 쉽게 읽고 유지 관리할 수 있습니다.

다음은 약속을 사용하는 이전 콜백 지옥 예시입니다.

getData()
 .then(data => processData(data))
 .then(processedData => saveData(processedData))
 .then(response => sendNotification(response))
 .then(notificationResult => {
 console.log("All done!");
 })
 .catch(error => {
 console.error("An error occurred:", error);
 });

이 접근 방식은 깊게 중첩된 콜백을 제거합니다. 각 'then' 블록은 체인의 다음 단계를 나타내며 흐름을 훨씬 더 선형적이고 따라가기 쉽게 만듭니다. 오류 처리도 'catch' 블록에 집중되어 있습니다.

약속이 작동하는 방식

약속에는 세 가지 상태가 있습니다.

  1. 보류 중: 약속이 아직 이행되거나 거부되지 않았음을 의미하는 초기 상태입니다.
  2. 이행됨: 비동기 작업이 성공적으로 완료되었습니다.
  3. 거부됨: 작업이 실패했습니다.

Promise 객체는 성공 및 실패 시나리오를 처리하기 위해 '.then()' 및 '.catch()' 메서드를 제공합니다.

function getData() {
 return new Promise((resolve, reject) => {
 // Simulating an async operation (e.g., API call)
 setTimeout(() => {
 const data = "Sample Data";
 resolve(data);
 }, 1000);
 });
}
getData()
 .then(data => {
 console.log("Data received:", data);
 })
 .catch(error => {
 console.error("Error fetching data:", error);
 });

위 코드에서 'getData()' 함수는 Promise를 반환합니다. 비동기 작업이 성공하면 약속이 데이터로 이행되고, 그렇지 않으면 오류와 함께 거부됩니다.

약속을 연결하다

Promise의 주요 장점 중 하나는 연결될 수 있다는 것입니다. 이를 통해 중첩 없이 비동기 작업 순서를 지정할 수 있습니다.

function fetchData() {
 return new Promise((resolve, reject) => {
 setTimeout(() => resolve("Data fetched"), 1000);
 });
}
function processData(data) {
 return new Promise((resolve, reject) => {
 setTimeout(() => resolve(`${data} and processed`), 1000);
 });
}
function saveData(data) {
 return new Promise((resolve, reject) => {
 setTimeout(() => resolve(`${data} and saved`), 1000);
 });
}
fetchData()
 .then(data => processData(data))
 .then(processedData => saveData(processedData))
 .then(result => {
 console.log(result); 
// Output => Data fetched and processed and saved
 })
 .catch(error => console.error("Error:", error));

Promise를 연결하면 코드가 단순해지고 읽기 쉬워지며 유지 관리가 쉬워집니다.

Async/Await: 훨씬 더 나은 대안

프라미스는 콜백에 비해 크게 개선되었지만 광범위한 체인을 사용하면 여전히 번거로울 수 있습니다. 여기가 async/await가 작동하는 곳입니다.
Async/await 구문을 사용하면 동기 코드와 유사한 방식으로 비동기 코드를 작성할 수 있습니다. 코드를 더 깔끔하고 추론하기 쉽게 만듭니다.

비동기/대기 사용:

async function performOperations() {
  try {
    const data = await getData();
    const processedData = await processData(data);
    const response = await saveData(processedData);
    const notificationResult = await sendNotification(response);

    console.log("All done!");
  } catch (error) {
    console.error("Error:", error);
  }
}

performOperations();

위 코드에서:

  • 'async' 키워드는 비동기 함수를 정의하는 데 사용됩니다.
  • 'await'는 프로미스가 해결되거나 거부될 때까지 함수 실행을 일시 중지하여 코드를 동기식으로 보이게 만듭니다.
  • 단일 'try-catch' 블록을 사용하면 오류 처리가 훨씬 간단해집니다.
  • Async/await는 콜백 지옥과 긴 약속 체인을 제거하여 현대 JavaScript에서 비동기 작업을 처리하는 데 선호되는 방법입니다.

결론

콜백 지옥은 여러 비동기 작업을 수행할 때 발생하는 JavaScript의 일반적인 문제입니다. 콜백이 깊게 중첩되면 유지 관리가 불가능하고 오류가 발생하기 쉬운 코드가 생성됩니다. 그러나 Promise 및 async/await의 도입으로 이제 개발자는 더 깔끔하고 관리하기 쉽고 확장 가능한 코드를 작성할 수 있습니다.

Promises 중첩된 콜백을 평면화하고 오류 처리를 중앙 집중화하는 반면, async/await는 비동기 로직을 ​​동기식으로 나타나게 하여 더욱 단순화합니다. 두 기술 모두 콜백 지옥의 혼란을 제거하고 코드가 복잡해지더라도 코드를 계속 읽을 수 있도록 보장합니다.

소셜 미디어 핸들
이 기사가 도움이 되었다면 내 소셜 미디어 채널에서 저에게 연락해 더 많은 통찰력을 얻으세요.

  • GitHub: [AmanjotSingh0908]
  • 링크드인: [Amanjot Singh Saini]
  • 트위터: [@AmanjotSingh]

읽어주셔서 감사합니다!

릴리스 선언문 이 기사는 https://dev.to/amanjotsingh/understanding-callback-hell-the-problem-solutions-and-code-examples-3loh?1에서 복제됩니다. 침해 사항이 있는 경우, [email protected]으로 문의해 주십시오. 그것을 삭제하려면
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3